﻿using System;
using System.Collections.Generic;
using System.Data.Odbc;
using MySql.Data.MySqlClient;
using Oracle.ManagedDataAccess.Client;
using System.Data.SqlClient;
using System.Data.SQLite;
using Npgsql;
using System.Text;
using System.Data.Common;
using System.Data;
//using LogCentre;
//using DataModel;

namespace DatabaseAccess
{
    /// <summary>
    /// Add or remove the supported type by adding or removing the related GetConnection or GetDbDataAdapter method.
    /// 可以根据支持的Sql类型增加或删除类型，需要增加或删除对应的GetConnection和GetDbDataAdapter方法。
    /// </summary>
    public enum SqlType
    {
        SqlServer,
        MySql,
        PostgresQL,
        Oracle,
        SQLite,
        //(ODBC ONLY) host system must have the data driver installed. ODBC data source is necessary if DSN is used.
        //对ODBC方式需要格外注意，目标系统必须预先安装有对应的数据驱动，如果使用DSN，那么还需要使用配置ODBC数据源
        Odbc
    }
    /// <summary>
    /// The class use ADO.NET access to database. It is thread safe if a single active object is used.
    /// 使用ADO.NET控制对数据库的基本访问方法，对同一个活动对象（不关闭）线程安全。
    /// </summary>
    public class DBAccess : IDisposable
    {
        protected DbConnection db;
        public DBAccess(string strDSN, SqlType sqlType)
        {
            _strDSN = strDSN;
            _sqlType = sqlType;
        }

        //public DBAccess(string strDSN)
        //{
        //    _strDSN = strDSN;
        //    //_sqlType = sqlType;
        //}

        //public DataTable GetAllPoints(string strSQL)
        //{
        //    DbConnection db = GetConnection();
        //    try
        //    {
        //        db.Open();
        //        DbDataAdapter adp = GetDbDataAdapter(strSQL, db);
        //        DataTable dt = new DataTable();
        //        adp.Fill(dt);
        //        return dt;
        //    }
        //    catch (Exception e)
        //    {
        //        //LogCentre.Log.logError($"写入数据错误{e.Message}");
        //        return null;
        //    }
        //    finally
        //    {
        //        db.Close();
        //        db.Dispose();
        //    }
        //}

        #region private variables
        private SqlType _sqlType;
        private string _strDSN;
        //private DbConnection db;
        private bool _disposed;
        #endregion

        #region private functions
        public DbConnection GetConnection()
        {
            DbConnection conn;
            switch (_sqlType)
            {
                case SqlType.SqlServer:
                    conn = new SqlConnection(_strDSN);
                    return conn;
                case SqlType.MySql:
                    conn = new MySqlConnection(_strDSN);
                    return conn;
                case SqlType.PostgresQL:
                    conn = new NpgsqlConnection(_strDSN);
                    return conn;
                case SqlType.Oracle:
                    conn = new OracleConnection(_strDSN);
                    return conn;
                case SqlType.SQLite:
                    conn = new SQLiteConnection(_strDSN);
                    return conn;
                case SqlType.Odbc:
                    conn = new OdbcConnection(_strDSN);
                    return conn;
                default:
                    return null;
            }
        }

        private DbDataAdapter GetDbDataAdapter(string sql, DbConnection db)
        {
            DbDataAdapter adp;
            switch (_sqlType)
            {
                case SqlType.SqlServer:
                    adp = new SqlDataAdapter(sql, db as SqlConnection);
                    return adp;
                case SqlType.MySql:
                    adp = new MySqlDataAdapter(sql, db as MySqlConnection);
                    return adp;
                case SqlType.PostgresQL:
                    adp = new NpgsqlDataAdapter(sql, db as NpgsqlConnection);
                    return adp;
                case SqlType.Oracle:
                    adp = new OracleDataAdapter(sql, db as OracleConnection);
                    return adp;
                case SqlType.SQLite:
                    adp = new SQLiteDataAdapter(sql, db as SQLiteConnection);
                    return adp;
                case SqlType.Odbc:
                    adp = new OdbcDataAdapter(sql, db as OdbcConnection);
                    return adp;
                default:
                    return null;
            }
        }

        internal DbCommand GetCommand(DbConnection conn, string strSQL)
        {
            DbCommand command = conn.CreateCommand();
            command.CommandText = strSQL;
            return command;
        }
        /// <summary>
        /// select 语句
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="strSQL"></param>
        /// <returns></returns>
        private DbDataReader GetDataReader(DbConnection conn, string strSQL)
        {
            //实例化OdbcCommand对象 
            DbCommand myCmd = GetCommand(conn, strSQL);
            DbTransaction transaction = conn.BeginTransaction(IsolationLevel.Snapshot);//读取采用快照锁，可以并行其他写入锁定，并行时使用旧数据做返回数据
            myCmd.Transaction = transaction;
            try
            {
                int ret = myCmd.ExecuteNonQuery();
                transaction.Commit();
                return myCmd.ExecuteReader();
            }
            catch(Exception ex)
            {
                transaction.Rollback();
                return null;
            }
        }
        #endregion

        /// <summary>
        /// Init a connection and open it.
        /// 初始化连接并打开
        /// </summary>
        /// <returns>true if successful</returns>
        public bool Init()
        {
            try
            {
                db = GetConnection();
                db.Open();
                return true;
            }
            catch (Exception e)
            {
                //log and exit
                //LogCentre.Log.logError(e.Message + e.InnerException);
                return false;
            }
        }

        public virtual DataTable getDataTable(string strSQL)
        {
            //这里需要一个连接的过程，连接成功后，调用基类的该程序。
            try
            {
                DbDataAdapter adp = GetDbDataAdapter(strSQL, db);
                DataTable dt = new DataTable();
                adp.Fill(dt);
                return dt;
            }
            catch (Exception e)
            {
                //LogCentre.Log.logError($"写入数据错误{e.Message}");
                return null;
            }
        }


        //public List<(int, int)> ExcuteQuery(string strSQL, string a = "1", string b = "1")
        //{
        //    DbConnection db = GetConnection();
        //    try
        //    {
        //        db.Open();
        //        DbDataReader myReader = GetDataReader(db, strSQL);
        //        List<(int, int)> p = new List<(int, int)>();
        //        while (myReader.Read())
        //        {
        //            p.Add((Convert.ToInt32(myReader[0]), Convert.ToInt32(myReader[1])));
        //        }
        //        return p;
        //    }
        //    catch(Exception e)
        //    {
        //        //LogCentre.Log.logError($"4ExcuteQuery{e.Message} data:{e.Data},sql:{strSQL}");
        //    }
        //    finally
        //    {
        //        db.Close();
        //        db.Dispose();
        //    }
        //    return new List<(int, int)>();
        //}



        //public DataTable taskExcuteQuery(string strSQL)
        //{
        //    DbConnection db = GetConnection();
        //    try
        //    {
        //        db.Open();
        //        DbDataAdapter adp = GetDbDataAdapter(strSQL, db);
        //        DataTable dt = new DataTable();
        //        adp.Fill(dt);
        //        return dt;
        //    }
        //    catch (Exception e)
        //    {
        //        //LogCentre.Log.logError($"写入数据错误{e.Message}");
        //        return null;
        //    }
        //    finally
        //    {
        //        db.Close();
        //        db.Dispose();
        //    }
        //}
        ///// <summary>
        ///// 获取任务ID
        ///// </summary>
        ///// <param name="strSQL"></param>
        ///// <returns></returns>
        //public int GetTaskId(string strSQL)
        //{
        //    DbConnection db = GetConnection();
        //    try
        //    {
        //        db.Open();
        //        using (DbDataReader myReader = GetDataReader(db, strSQL))
        //        {
        //            int id = 0 ;
        //            while (myReader.Read())
        //            {
        //                id = Convert.ToInt32(myReader[0]);
        //            }
        //            return id;
        //        }
        //    }
        //    catch (Exception e)
        //    {
        //        //LogCentre.Log.logError($"获取任务ID失败：{e.Message} data:{e.Data},sql:{strSQL}");
        //        StringBuilder sb = new StringBuilder();
        //        sb.Clear();
        //        sb.Append("获取数据失败！");
        //        sb.Append("sql: "+ strSQL);
        //        sb.Append(" " + e.ToString());

        //        //Log.Error(sb.ToString(), false);
        //        return 0;
        //    }
        //    finally
        //    {
        //        db.Close();
        //        db.Dispose();
        //    }
        //}

        ///// <summary>
        ///// 获取任务ID
        ///// </summary>
        ///// <param name="strSQL"></param>
        ///// <returns></returns>
        //public double GetScalarDouble(string strSQL)
        //{
        //    DbConnection db = GetConnection();
        //    try
        //    {
        //        db.Open();

        //        DbCommand myCmd = GetCommand(db, strSQL);
        //        return Convert.ToDouble(myCmd.ExecuteScalar());
        //    }
        //    catch (Exception e)
        //    {
        //        return 0d;
        //    }
        //    finally
        //    {
        //        db.Close();
        //        db.Dispose();
        //    }
        //}

        //public List<(int, int, int)> ExcuteQuery(string strSQL, string a ="1")
        //{
        //    DbConnection db = GetConnection();
        //    try
        //    {
        //        db.Open();
        //        using (DbDataReader myReader = GetDataReader(db, strSQL))
        //        {
        //            List<(int, int, int)> p = new List<(int, int, int)>();
        //            while (myReader.Read())
        //            {
        //                p.Add((Convert.ToInt32(myReader[0]), Convert.ToInt32(myReader[1]), Convert.ToInt32(myReader[2])));
        //            }
        //            return p;
        //        }
        //    }
        //    catch (Exception e)
        //    {
        //        //LogCentre.Log.logError($"3ExcuteQuery{e.Message} data:{e.Data},sql:{strSQL}");
        //        return new List<(int, int, int)>();
        //    }
        //    finally
        //    {
        //        db.Close();
        //        db.Dispose();
        //    }
        //}


        //public List<(double, int, int, int, double)> ExcuteQuery5(string strSQL)
        //{
        //    DataTable dt = taskExcuteQuery(strSQL);
        //    List<(double, int, int, int, double)> p = new List<(double, int, int, int, double)>();
        //    if ((dt != null) && (dt.Rows.Count > 0))
        //    {
        //        foreach (DataRow dr in dt.Rows)
        //        {
        //            try
        //            {
        //                double.TryParse(dr[0].ToString(), out double num1);
        //                int.TryParse(dr[1].ToString(), out int num2);
        //                int.TryParse(dr[2].ToString(), out int num3);
        //                int.TryParse(dr[3].ToString(), out int num4);
        //                double.TryParse(dr[4].ToString(), out double num5);

        //                p.Add((num1, num2, num3, num4, num5));
        //            }
        //            catch (Exception ex)
        //            {
        //                ;
        //            }
        //        }
        //    }
        //    return p;
        //}

        //public List<(int, int, int)> ExcuteQuery3(string strSQL)
        //{
        //    DataTable dt = taskExcuteQuery(strSQL);
        //    List<(int, int, int)> p = new List<(int, int, int)>();
        //    if ((dt != null) && (dt.Rows.Count > 0))
        //    {
        //        foreach (DataRow dr in dt.Rows)
        //        {
        //            try
        //            {
        //                int.TryParse(dr[0].ToString(), out int num1);
        //                int.TryParse(dr[1].ToString(), out int num2);
        //                int.TryParse(dr[2].ToString(), out int num3);

        //                p.Add((num1, num2, num3));
        //            }
        //            catch (Exception ex)
        //            {
        //                ;
        //            }
        //        }
        //    }
        //    return p;
        //}

        //public List<(int, int, int,int)> ExcuteQuery(string strSQL, string a = "1",double b=1.0)
        //{
        //    DbConnection db = GetConnection();
        //    try
        //    {
        //        db.Open();
        //        using (DbDataReader myReader = GetDataReader(db, strSQL))
        //        {
        //            List<(int, int, int, int)> p = new List<(int, int, int, int)>();
        //            if (myReader == null) { return p; }
        //            while (myReader.Read())
        //            {
        //                p.Add((Convert.ToInt32(myReader[0]), Convert.ToInt32(myReader[1]), Convert.ToInt32(myReader[2]), Convert.ToInt32(myReader[3])));
        //            }
        //            return p;
        //        }
        //    }
        //    catch (Exception e)
        //    {
        //        //LogCentre.Log.logError($"2ExcuteQuery{e.Message} data:{e.Data},sql:{strSQL}");
        //        return new List<(int, int, int,int)>();
        //    }
        //    finally
        //    {
        //        db.Close();
        //        db.Dispose();
        //    }
        //}
        //public List<(int, int)> ExcuteQuery(string strSQL, string a = "1",bool b=true)
        //{
        //    DbConnection db = GetConnection();
        //    try
        //    {
        //        db.Open();
        //        using (DbDataReader myReader = GetDataReader(db, strSQL))
        //        {
        //            List<(int, int)> p = new List<(int, int)>();
        //            while (myReader.Read())
        //            {
        //                p.Add(((int)Convert.ToDouble(myReader[0]), (int)Convert.ToDouble(myReader[1])));
        //            }
        //            return p;
        //        }
        //    }
        //    catch (Exception e)
        //    {
        //        //LogCentre.Log.logError($"1ExcuteQuery{e.Message} data:{e.Data},sql:{strSQL}");
        //        return new List<(int, int)>();
        //    }
        //    finally
        //    {
        //        db.Close();
        //        db.Dispose();
        //    }
        //}
        //public int ExcuteQuery(string strSQL, bool a = true, bool b = true, bool c = true)
        //{
        //    DbConnection db = GetConnection();
        //    try
        //    {
        //        db.Open();
        //        using (DbDataReader myReader = GetDataReader(db, strSQL))
        //        {
        //            int p = 0;
        //            while (myReader.Read())
        //            {
        //                if (myReader[0] == null || myReader[0] == DBNull.Value)
        //                {
        //                    return 0;
        //                }
        //                p = Convert.ToInt32(myReader[0]);
        //            }
        //            return p;
        //        }
        //    }
        //    catch (Exception e)
        //    {
        //        //LogCentre.Log.logError($"ExcuteQuery{e.Message} data:{e.Data},sql:{strSQL}");
        //        return 0;
        //    }
        //    finally
        //    {
        //        db.Close();
        //        db.Dispose();
        //    }
        //}
        ////public 
        ///// <summary>
        ///// 获取所有的数据点
        ///// </summary>
        ///// <param name="strSQL"></param>
        ///// <param name="a"></param>
        ///// <param name="b"></param>
        ///// <returns></returns>
        //public Dictionary<(int, int), int> ExcuteQuery(string strSQL, bool a = true, bool b = true)
        //{
        //    Dictionary<(int, int), int> pinoLit = new Dictionary<(int, int), int>();
        //    using (DbDataReader myReader = GetDataReader(db, strSQL))
        //    {
        //        while (myReader.Read())
        //        {
        //            try
        //            {
        //                if (myReader.FieldCount == 3)
        //                {
        //                    pinoLit[((int)myReader[0], (int)myReader[1])] = (int)myReader[2];
        //                }
        //            }
        //            catch (Exception e)
        //            {
        //                //LogCentre.Log.logError($"sql读取数据错误{e.Message}");
        //            }
        //        }
        //    }
        //    return pinoLit;
        //}
      
        /// <summary>
        /// 执行非Select语句，包括UPDATE DELETE INSERT
        /// </summary>
        /// <param name="strSQL">需要执行的sql语句</param>
        /// <returns>受影响的行数</returns>
        public virtual int ExcuteNonQuery(string strSQL)
        {
            DbConnection db = GetConnection();
            try
            {
                db.Open();
                //实例化OdbcCommand对象
                DbCommand myCmd = GetCommand(db, strSQL);
                int ret = myCmd.ExecuteNonQuery();
                myCmd.Dispose();
                //db.Close();
                //db.Dispose();
                return ret;
            }
            catch (Exception e)
            {
                //LogCentre.Log.logError($"执行非Select语句错误:{e.Message},date:{e.StackTrace},obj:{strSQL}");
                return 0;
            }
            finally
            {
                db.Close();
                db.Dispose();
            }
        }
        ///// <summary>
        ///// 通过事务批量执行非查询SQL语句
        ///// </summary>
        ///// <param name="strSQLs">需要批量执行的SQL</param>
        ///// <returns>受影响的行数，发生回滚则返回-1</returns>
        //public int ExecuteNonQueryTransaction(List<string> strSQLs)
        //{
        //    DbCommand myCmd = GetCommand(db, "");
        //    int sumAffected = 0;

        //    DbTransaction transaction = db.BeginTransaction();
        //    myCmd.Transaction = transaction;

        //    try
        //    {
        //        foreach (var n in strSQLs)
        //        {
        //            myCmd.CommandText = n;
        //            sumAffected += myCmd.ExecuteNonQuery();
        //        }
        //        transaction.Commit();
        //        return sumAffected;
        //    }
        //    catch (Exception e)
        //    {
        //        Log.Error(e);
        //        transaction.Rollback();
        //        return -1;
        //    }
        //}

        ///// <summary>
        ///// 通过事务批量执行非查询SQL语句
        ///// </summary>
        ///// <param name="strSQLs">需要批量执行的SQL</param>
        ///// <returns>受影响的行数，发生回滚则返回-1</returns>
        //public int ExecuteTransaction(List<string> strSQLs)
        //{
        //    DbConnection db = GetConnection();
        //    if (db == null)
        //        return -1;

        //    DbCommand myCmd = GetCommand(db, "");
        //    int sumAffected = 0;

        //    DbTransaction transaction;
        //    try
        //    {
        //        db.Open();
        //        if (db.State != ConnectionState.Open)
        //            return -1;
        //        transaction = db.BeginTransaction();
        //        myCmd.Transaction = transaction;
        //    }
        //    catch (Exception ex)
        //    {
        //        Log.Error(ex);
        //        return -1;
        //    }

        //    try
        //    {
        //        foreach (var n in strSQLs)
        //        {
        //            myCmd.CommandText = n;
        //            int geshu = myCmd.ExecuteNonQuery();
        //            if (geshu <=0)
        //            {
        //                ;
        //            }
        //            sumAffected += geshu;
        //        }
        //        transaction.Commit();
        //        return sumAffected;
        //    }
        //    catch (Exception e)
        //    {
        //        Log.Error(e);
        //        transaction.Rollback();
        //        return -1;
        //    }
        //    finally
        //    {
        //        db.Close();
        //        db.Dispose();
        //    }
        //}

        ///// <summary>
        ///// 执行非查询SQL，使用Oracle的Blob对象
        ///// </summary>
        ///// <param name="sql">需要执行的sql语句，语句中有且仅有一个‘:blob’参数</param>
        ///// <param name="path">需要插入的blob文件路径</param>
        ///// <returns>受影响的行数，执行不成功则返回-1</returns>
        //public int OracleBlobNonQuery(string sql, string path)
        //{
        //    if (!(db is OracleConnection))
        //    {
        //        return -1;
        //    }

        //    //OracleCommand cmd = new OracleCommand("INSERT INTO TEST SET F2 =:blob", db as OracleConnection);
        //    OracleCommand cmd = new OracleCommand(sql, db as OracleConnection);

        //    cmd.Parameters.Add(new OracleParameter("blob", OracleDbType.Blob));
        //    FileInfo fi = new FileInfo(path);
        //    var mydata = File.ReadAllBytes(path);
        //    cmd.Parameters["blob"].Value = mydata;
        //    try
        //    {
        //        return cmd.ExecuteNonQuery();
        //    }
        //    catch (Exception e)
        //    {
        //        Log.Error(e);
        //        return -1;
        //    }
        //}

        ///// <summary>
        ///// 执行非查询SQL，使用SQL Server的Image对象
        ///// </summary>
        ///// <param name="sql">需要执行的sql语句，语句中有且仅有一个‘@blob’参数</param>
        ///// <param name="path">需要插入的blob文件路径</param>
        ///// <returns>受影响的行数，执行不成功则返回-1</returns>
        //public int SqlImageNonQuery(string sql, string path)
        //{
        //    if (!(db is SqlConnection))
        //    {
        //        return -1;
        //    }

        //    //SqlCommand cmd = new SqlCommand("INSERT INTO TEST SET F2 =@blob", db as SqlConnection);
        //    SqlCommand cmd = new SqlCommand(sql, db as SqlConnection);

        //    cmd.Parameters.Add(new SqlParameter("@blob", SqlDbType.Image));
        //    FileInfo fi = new FileInfo(path);
        //    var mydata = File.ReadAllBytes(path);
        //    cmd.Parameters["@blob"].Value = mydata;
        //    try
        //    {
        //        return cmd.ExecuteNonQuery();
        //    }
        //    catch (Exception e)
        //    {
        //        Log.Error(e);
        //        return -1;
        //    }
        //}

        //public int BulkInsertNpg(List<(int x, int y, int z)> xyz)
        //{
        //    using (var writer = ((NpgsqlConnection)db).BeginBinaryImport("COPY mesh (x,y,z) FROM STDIN (FORMAT BINARY)"))
        //    {
        //        foreach (var n in xyz)
        //        {
        //            writer.StartRow();
        //            writer.Write(n.x, NpgsqlDbType.Integer);
        //            writer.Write(n.y, NpgsqlDbType.Integer);
        //            writer.Write(n.z, NpgsqlDbType.Integer);
        //        }
        //    }
        //    return 0;
        //}

        //public Dictionary<(int , int ), int> BulkIQueryNpg(string tableName)
        //{
        //    Dictionary<(int, int), int> dict = new Dictionary<(int, int), int>();
        //    //StringBuilder sb = new StringBuilder();
        //    //sb.Clear();
        //    //sb.Append("COPY (");
        //    //sb.Append("select x,y,z from "+tableName+" where x%500=0 and y%500=0 ");
        //    //sb.Append("or");
        //    //sb.Append("z > (select max(z)-5000 from " + tableName + ")");
        //    //sb.Append("or");
        //    //sb.Append("z < (select max(z)+5000 from " + tableName + ")");
        //    //sb.Append(" TO STDOUT (FORMAT BINARY)");

        //    using (var reader = ((NpgsqlConnection)db).BeginBinaryExport($"COPY (select x,y,z from {tableName} where x%500=0 and y%500=0 " +
        //        $"or z > (select max(z)-5000 from {tableName}) or z <(select min(z)+5000  from {tableName})) " +
        //        $" TO STDOUT (FORMAT BINARY)"))
        //    {
        //        while (reader.StartRow() != -1)
        //        {
        //            var x = reader.Read<int>(NpgsqlDbType.Integer);
        //            var y = reader.Read<int>(NpgsqlDbType.Integer);
        //            var z = reader.Read<int>(NpgsqlDbType.Integer);
        //            dict[(x, y)] = z;
        //        }
        //    }
        //    return dict;
        //}

        ///// <summary>
        ///// 更新任务状态
        ///// </summary>
        ///// <param name="sql"></param>
        ///// <returns></returns>
        //public int BulkBatInsertNpg(string sql)
        //{
        //    DbConnection db = GetConnection();
        //    try
        //    {
        //        db.Open();
        //        //实例化OdbcCommand对象
        //        DbCommand myCmd = GetCommand(db, sql);
        //        int ret = myCmd.ExecuteNonQuery();
        //        myCmd.Dispose();
        //        return ret;
        //    }
        //    catch (Exception e)
        //    {
        //        //LogCentre.Log.logError($"执行非Select语句错误:{e.Message},date:{e.StackTrace},obj:{sql}");
        //        return 0;
        //    }
        //    finally
        //    {
        //        db.Close();
        //        db.Dispose();
        //    }
        //}
        //public void BulkInsertNpgTs(List<(int x, int y, int z)> xyz)
        //{

        //    using (var cmd = ((NpgsqlConnection)db).CreateCommand())
        //    {
        //        cmd.CommandText = "INSERT INTO mesh(x,y,z) values(:x,:y,:z) on conflict (x,y) do update set z = excluded.z";
        //        cmd.Parameters.Add("x", NpgsqlDbType.Integer);
        //        cmd.Parameters.Add("y", NpgsqlDbType.Integer);
        //        cmd.Parameters.Add("z", NpgsqlDbType.Integer);
        //        cmd.Prepare();
        //        foreach (var n in xyz)
        //        {
        //            cmd.Parameters[0].Value = n.x;
        //            cmd.Parameters[1].Value = n.y;
        //            cmd.Parameters[2].Value = n.z;
        //            cmd.ExecuteNonQuery();
        //        }
        //    }
        //    return;
        //}
        //public class xyzPiont
        //{
        //    public int x { get; set; }
        //    public int y { get; set; }
        //    public int z { get; set; }
        //}
        //public int BulkInsertNpgT(IDictionary<(int x, int y), (int, int, int)> bag, string tableName)
        //{
        //    List<StringBuilder> listbuilder = new List<StringBuilder>();
        //    List<StringBuilder> listdelete = new List<StringBuilder>();
        //    StringBuilder sb = new StringBuilder();
        //    StringBuilder del = new StringBuilder();
        //    int i = 0;
        //    List<KeyValuePair<(int, int), int>> outxyz = new List<KeyValuePair<(int, int), int>>();
        //    foreach (var n in bag)
        //    {
        //        if (i % 700 == 0)
        //        {
        //            if (i != 0)
        //                sb.Append(" on conflict (keyx,keyy) do update set z = excluded.z, x = excluded.x, y = excluded.y");
        //            sb = new StringBuilder();
        //            listbuilder.Add(sb);
        //            sb.Append($"insert into {tableName}(keyx,keyy,x,y,z) values");
        //            sb.Append($"({n.Key.x}, {n.Key.y}, {n.Value.Item1}, {n.Value.Item2}, {n.Value.Item3})");
        //        }
        //        else
        //        {
        //            sb.Append($",({n.Key.x}, {n.Key.y},{n.Value.Item1}, {n.Value.Item2}, {n.Value.Item3})");
        //        }
        //        i++;
        //    }
        //    if (!sb.ToString().EndsWith("y"))
        //        sb.Append(" on conflict (keyx,keyy) do update set z = excluded.z, x = excluded.x, y = excluded.y");
        //    int count = 0;
        //    foreach (var n in listbuilder)
        //    {
        //        int sqlState = ExcuteNonQuery(n.ToString());
        //        count+=sqlState;
        //    }
        //    return count;
        //}

        //public int BulkInsertNpgT(IDictionary<(int x, int y), int> bag, string tableName)
        //{
        //    List<StringBuilder> listbuilder = new List<StringBuilder>();
        //    List<StringBuilder> listdelete = new List<StringBuilder>();
        //    StringBuilder sb = new StringBuilder();
        //    StringBuilder del = new StringBuilder();
        //    int i = 0;
        //    List<KeyValuePair<(int, int), int>> outxyz = new List<KeyValuePair<(int, int), int>>();
        //    foreach (var n in bag)
        //    {
        //        if (i % 1000 == 0)
        //        {
        //            if (i != 0) 
        //                sb.Append(" on conflict (x,y) do update set z = excluded.z ");
        //            sb = new StringBuilder();
        //            listbuilder.Add(sb);
        //            sb.Append($"insert into {tableName}(x,y,z) values");
        //            sb.Append($"({n.Key.x}, {n.Key.y}, {n.Value})");
        //        }
        //        else
        //        {
        //            sb.Append($",({n.Key.x}, {n.Key.y},{n.Value})");
        //        }
        //        i++;
        //    }
        //    if (!sb.ToString().EndsWith("y")) 
        //        sb.Append(" on conflict (x,y) do update set z = excluded.z ");
        //    int count = 0;
        //    foreach (var n in listbuilder)
        //    {
        //        int sqlState = ExcuteNonQuery(n.ToString());
        //        count += sqlState;
        //    }
        //    return count;
        //}
        #region 资源清理
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    //托管对象释放
                }
                //非托管对象释放
                if (db != null)
                {
                    if (db.State != ConnectionState.Closed)
                    {
                        db.Close();
                    }
                    else
                    {
                        db = null;
                    }
                }
                _disposed = true;
            }
        }

        ~DBAccess()
        {
            Dispose(false);
        }
        #endregion
    }
}
